import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import Stats from 'three/examples/jsm/libs/stats.module.js'
import { GUI } from 'three/examples/jsm/libs/dat.gui.module.js'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls'
const initStats = (type) => {
  // eslint-disable-next-line no-extra-parens
  const panelType = (typeof type !== 'undefined' && type) && (!isNaN(type)) ? parseInt(type, 10) : 0
  const stats = new Stats()
  stats.showPanel(panelType)
  document.body.appendChild(stats.dom)
  return stats
}
export default () => {
  // 渲染监听器
  const stats = initStats()
  // 定义属性 旋转速度和跳动速度
  const controls = {
    'rotationSpeed': 0.02,
    'bouncingSpeed': 0.03
  }
  // GUI 面板
  const gui = new GUI()
  gui.add(controls, 'rotationSpeed', 0, 0.5)
  gui.add(controls, 'bouncingSpeed', 0, 0.5)
  // 定义了场景
  // 场景是一个容器，用于保存、跟踪索要渲染的物体和使用的光源
  const scene = new THREE.Scene()
  // 定义雾化效果
  scene.fog = new THREE.Fog(0xffffff, 0, 300)
  // 定义了摄像机
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
  // 定义了渲染器
  // 该对象会基于摄像机的角度来计算场景对象在浏览器渲染成什么样子
  const renderer = new THREE.WebGLRenderer()
  // 设置场景背景色
  renderer.setClearColor(new THREE.Color(0x000000))
  // 设置场景大小
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 渲染阴影需要消耗大量的资源，所以默认是不渲染的，所以我们需要手动打开阴影渲染
  renderer.shadowMap.enabled = true

  // 设置坐标轴，粗细为20，并添加到场景中
  const axes = new THREE.AxesHelper(20)
  scene.add(axes)

  // 创建一个平面，并定义大小 60*20
  const planeGeometry = new THREE.PlaneGeometry(60, 20)
  // 用材质来设置平面样式
  // 创建平面颜色，用基本材质来创建，颜色为 0xAAAAAA MeshBasicMaterial为基本材质
  // const planeMeterial = new THREE.MeshBasicMaterial({
  //   'color': 0xAAAAAA
  // })
  // 为了让光源生效，我们改变其材质
  const planeMeterial = new THREE.MeshLambertMaterial({ 'color': 0xffffff })
  const plane = new THREE.Mesh(planeGeometry, planeMeterial)
  // 将平面绕X轴旋转90度
  plane.rotation.x = -0.5 * Math.PI
  // 定义平面在场景中的位置
  plane.position.set(15, 0, 0)
  // 设置平面接受阴影
  plane.receiveShadow = true
  // 将平面添加到场景中
  scene.add(plane)

  // 下面以同样的方式创建方块和球体

  // create cub
  const cubeGeometry = new THREE.BoxGeometry(4, 4, 4)
  const cubeMaterial = new THREE.MeshLambertMaterial({
    'color': 0xFF0000
    // 'wireframe': true // 该属性可以不将物体渲染为实体
  })
  const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
  cube.position.set(-4, 3, 0)
  // 设置该物体投射阴影
  cube.castShadow = true
  scene.add(cube)

  // create a sphere
  const sphereGeometry = new THREE.SphereGeometry(4, 20, 20)
  const sphereMaterial = new THREE.MeshLambertMaterial({
    'color': 0x7777FF
    // 'wireframe': true
  })
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
  sphere.position.set(20, 4, 2)
  // 设置该物体投射阴影
  sphere.castShadow = true
  scene.add(sphere)

  // 添加光源
  const spotLight = new THREE.SpotLight(0xFFFFFF)
  // 光源从该位置照射场景
  spotLight.position.set(-40, 40, -15)
  // 开启阴影
  spotLight.castShadow = true
  // 控制阴影精细度
  spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024)
  spotLight.shadow.camera.far = 130
  spotLight.shadow.camera.near = 40
  // 将光源加入场景
  scene.add(spotLight)

  // position and point the camera to the center of the scene
  camera.position.set(-30, 40, 30)
  // 将相机指向场景中心
  camera.lookAt(scene.position)

  // add the output of the renderer to the html element
  document.getElementById('webGlContainer').appendChild(renderer.domElement)
  // 实现鼠标移动摄像头
  const trackballControls = new TrackballControls(camera, renderer.domElement)
  const clock = new THREE.Clock()

  // render the scene
  let step = 0
  function renderScene () {
    stats.update() // 渲染完每一帧后更新统计
    trackballControls.update(clock)
    // 旋转立方体
    cube.rotation.x += controls.rotationSpeed
    cube.rotation.y += controls.rotationSpeed
    cube.rotation.z += controls.rotationSpeed
    // 让小球跳起来
    step += controls.bouncingSpeed
    sphere.position.x = 20 + 10 * Math.cos(step)
    sphere.position.y = 2 + 10 * Math.abs(Math.sin(step))

    requestAnimationFrame(renderScene)
    renderer.render(scene, camera)
  }
  renderScene()

  // 适配浏览器场景大小
  const onResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
  window.addEventListener('resize', onResize, false)
}
